-module(ect_v2_calltest).

-define(BRANCHES,100).
-define(RUNS,1000).

-export([test/0]).

add_module(NameAtom, FileName, Forms) ->
   % my_pp:print(Forms, FileName++".txt", false),
    Binary = 
        case compile:forms(Forms) of
        {ok,NameAtom,BinaryOrCode} -> BinaryOrCode;
        {ok,NameAtom,BinaryOrCode, Warnings} -> BinaryOrCode
        end,
    code:load_binary(NameAtom, "**"++FileName++"**", Binary).

create_scenA(N) when N > 0 ->
    Name = "item"++integer_to_list(N),
    NameAtom = list_to_atom(Name),
    Forms = 
        [{attribute, 1, file, {Name++".txt", 1}}
        ,{attribute, 1, module, NameAtom}
        ,{attribute, 1, export, [{test, 2}]}
        ,{function, 2, test, 2,
            [{clause, 2
             ,[{var, 2, 'N'}, {var, 2, '_'}]
             ,[]
             ,[{op, 2, case N rem 2 of 0 -> '+'; 1 -> '-' end, {var, 2, 'N'}, {integer, 2, 1}}]
             %,[{var, 2, 'N'}]
             }
            ]
         }
        ,{eof, 3}],
    add_module(NameAtom, Name, Forms),
    create_scenA(N-1);
create_scenA(0) ->
    ok.

create_scenB_clauses(N) when N > 0 ->
    [{clause, 3,
        [{atom, 3, list_to_atom("item"++integer_to_list(N))}
        ,{var, 3, 'N'}, {var, 3, '_'}
        ],
        [],
        [{op, 2, case N rem 2 of 0 -> '+'; 1 -> '-' end, {var, 2, 'N'}, {integer, 2, 1}}]
     }
    |create_scenB_clauses(N-1)
    ];
create_scenB_clauses(0) ->
    [].

create_scenB(N) ->
    Name = "itemB",
    NameAtom = list_to_atom(Name),
    Forms = 
        [{attribute, 1, file, {Name++".txt", 1}}
        ,{attribute, 1, module, NameAtom}
        ,{attribute, 1, export, [{test, 3}]}
        ,{function, 2, test, 3, 
            create_scenB_clauses(N)
         }
        ,{eof, 4}
        ],
    add_module(NameAtom, Name, Forms).

gen_tester_function_body(GenCall, Name, N) when N > 0 ->
    %Module = list_to_atom("item"++integer_to_list(N)),
    XAtom1 = list_to_atom("X"++integer_to_list(N)),
    XAtom2 = list_to_atom("X"++integer_to_list(N-1)),
    [{match, 2, 
        {var, 2, XAtom2},
        GenCall(N, XAtom1)
    }]++gen_tester_function_body(GenCall, Name, N-1);
gen_tester_function_body(_, Name, 0) ->
    [{call, 2, {atom, 2, Name}, [{op, 2, '-', {var, 2, 'N'}, {integer, 2, 1}}, {var, 2, 'X0'}]}].

gen_tester_function(GenCall, Name) ->
    {function, 2, Name, 2,
            [{clause, 2,
                [{var, 2, 'N'}, {var, 2, list_to_atom("X"++integer_to_list(?BRANCHES)) }],
                [[{op, 2, '>', {var, 2, 'N'}, {integer, 2, 0}}]],
                %[],
                gen_tester_function_body(GenCall, Name, ?BRANCHES)
             }
            ,{clause, 3,
                [{integer, 3, 0}, {var, 3, 'X'}],
                [],
                [{var, 3, 'X'}]
             }
            ]
    }.

create_tester() ->
    Name = "tester",
    NameAtom = list_to_atom(Name),
    Forms = 
        [{attribute, 1, file, {Name++".txt", 1}}
        ,{attribute, 1, module, NameAtom}
        ,{attribute, 1, export, [{testA, 2}, {testB, 2}]}
        ,gen_tester_function(fun (N, ParamVar) ->
                                Module = list_to_atom("item"++integer_to_list(N)),
                                {call, 2, {remote, 2, {atom, 2, Module}, {atom, 2, test}}, [{var, 2, ParamVar}, {atom, 2, semmi}]}
                             end, testA)
        ,gen_tester_function(fun (N, ParamVar) ->
                                Id = list_to_atom("item"++integer_to_list(N)),
                                {call, 2, {remote, 2, {atom, 2, itemB}, {atom, 2, test}}, [{atom, 2, Id}, {var, 2, ParamVar}, {atom, 2, semmi}]}
                             end, testB)
        ,{eof, 4}
        ],
    add_module(NameAtom, Name, Forms).


test() ->
    create_tester(),

    create_scenB(?BRANCHES),
    {B,_} = timer:tc(tester, testB, [?RUNS, 0]),

    create_scenA(?BRANCHES),
    {A,_} = timer:tc(tester, testA, [?RUNS, 0]),
    N = ?RUNS*?BRANCHES,
 %   io:format("~p ~p~n", [A, N]),
    {"distributed:", A/N, "central:", B/N}.
